﻿using System;
using System.Collections.Generic;

namespace Gonte.Wpf.Controls.ViewModel.Searching
{
    /// <summary>
    /// Searches for items in the view model
    /// </summary>
    public class ViewModelSearcher
    {
        public ViewModelSearcher(ContentViewModel viewModel)
        {
            ExceptionThrower.ThrowWhenNull("viewModel", viewModel);

            _viewModel = viewModel;
        }

        public bool Search()
        {
            ExceptionThrower.ThrowWhenNull("IsMatch", _isMatch);

            // Deselect any previous selected view model
            if (null != _selectedViewModel)
            {
                _selectedViewModel.IsSelected = false;
            }

            if (null == _matchedEnumerator
                || !_matchedEnumerator.MoveNext())
            {
                IEnumerable<ItemViewModel> matches = FindMatches(_searchText, _viewModel);
                _matchedEnumerator = matches.GetEnumerator();

                if (!_matchedEnumerator.MoveNext())
                {
                    return false;
                    //MessageBox.Show(
                    //    "No matching names were found.",
                    //    "Try Again",
                    //    MessageBoxButton.OK,
                    //    MessageBoxImage.Information
                    //    );
                }
            }

            ItemViewModel viewModel = _matchedEnumerator.Current;

            if (null == viewModel)
            {
                return false;
            }

            // Ensure that this item is in view.
            if (viewModel.Parent != null)
            {
                viewModel.Parent.IsExpanded = true;
            }

            viewModel.IsSelected = true;
            _selectedViewModel = viewModel;

            return true;
        }

        public String SearchText
        {
            get { return _searchText; }

            set
            {
                if (
                    (_searchText == null && !String.IsNullOrEmpty(value))
                    || (_searchText != null && !_searchText.Equals(value))
                    )
                {
                    _searchText = value;
                    _matchedEnumerator = null;
                }
            }
        }

        IEnumerable<ItemViewModel> FindMatches(string searchText, ItemViewModel viewModel)
        {
            if (_isMatch(searchText, viewModel))
            {
                yield return viewModel;
            }

            ContentViewModel contentViewModel = viewModel as ContentViewModel;

            if (null != contentViewModel)
            {
                foreach (ItemViewModel childViewModel in contentViewModel.Children)
                {
                    foreach (ItemViewModel matchViewModel in FindMatches(searchText, childViewModel))
                    {
                        yield return matchViewModel;
                    }
                }
            }
        }

        #region Match handler

        public delegate bool IsMatchHandler(string searchText, ItemViewModel viewModel);
        private IsMatchHandler _isMatch;

        public IsMatchHandler IsMatch
        {
            get { return _isMatch; }
            set { _isMatch = value; }
        }

        #endregion

        #region Fields

        private ContentViewModel _viewModel;
        private string _searchText;
        private IEnumerator<ItemViewModel> _matchedEnumerator;

        private ItemViewModel _selectedViewModel;

        #endregion
    }
}
